import Vue from 'vue';
export const isIE = function() {
  return !Vue.prototype.$isServer && !isNaN(Number(document.documentMode));
};

export const isEdge = function() {
  return !Vue.prototype.$isServer && navigator.userAgent.indexOf('Edge') > -1;
};

export const isFirefox = function() {
  return !Vue.prototype.$isServer && !!window.navigator.userAgent.match(/firefox/i);
};

/**
 * @description: 防抖函数
 * @param {Function} fn 待执行函数
 * @param {Number} wait 等待时间
 * @return {Function} 待执行的防抖函数
 */
export const debounce = (fn, wait) => {
  let timer = null;
  return function () {
    let context = this,
      args = arguments;
    if (timer) {
      clearTimeout(timer);
      timer = null;
    } else {
      fn.apply(context, args);
    }
    timer = setTimeout(() => {
      timer = null;
    }, wait);
  };
};

/**
 * @description: 节流函数
 * @param {Function} fn 待执行函数
 * @param {Number} wait 等待时间
 * @return {Function} 待执行的节流函数
 */
export const throttle = (fn, delay) => {
  let curTime = Date.now();
  return function () {
    let context = this,
      args = arguments,
      nowTime = Date.now();

    if (nowTime - curTime >= delay) {
      curTime = Date.now();
      return fn.apply(context, args);
    }
  };
};

/**
 * @description: 生成z-index的style
 * @param {Number | String} zIndex
 * @return {Object} style字典
 */
export function getZIndexStyle(zIndex) {
  const style = {};
  if (zIndex !== undefined) {
    style.zIndex += zIndex;
  }
  return style;
}

/**
 * @description: 深拷贝
 * @param {any} target 拷贝目标
 * @return {any} 拷贝结果
 */
export function deepClone(target) {
  if (typeof (target) !== 'object') {
    return target;
  }
  let result;
  if (Object.prototype.toString.call(target) == '[object Array]') {
    // 数组
    result = [];
  } else {
    // 对象
    result = {};
  }
  for (let prop in target) {
    if (Object.prototype.hasOwnProperty.call(target, prop)) {
      if (target[prop] === null) {
        result[prop] = null;
      } else {
        result[prop] = deepClone(target[prop]);
      }
      
    }
  }
  return result;
}

function extend(to, _from) {
  for (let key in _from) {
    to[key] = _from[key];
  }
  return to;
}
export function toObject(arr) {
  var res = {};
  for (let i = 0; i < arr.length; i++) {
    if (arr[i]) {
      extend(res, arr[i]);
    }
  }
  return res;
}

export function isString(data) {
  return Object.prototype.toString.call(data) === '[object String]';
}

export const isNumber = (data) => {
  return Object.prototype.toString.call(data) === '[object Number]';
};

export function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

export function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

export function isPromise(obj) {
  return Object.prototype.toString.call(obj) === '[object Promise]';
}

export const isFunction = (functionToCheck) => {
  return Object.prototype.toString.call(functionToCheck) === '[object Function]' || Object.prototype.toString.call(functionToCheck) === '[object AsyncFunction]';
};

export const isDomElement = (element) => {
  return element && typeof element === 'object' && 'nodeType' in element;
};

export function isNull(value) {
  return Object.prototype.toString.call(value).toLowerCase() === '[object null]';
}

export function isUndefined(value) {
  return Object.prototype.toString.call(value).toLowerCase() === '[object undefined]';
}

/**
 * @description: Bem类
 * @param {String} b  Block命名空间
 */
// const {b, e} = new Bem('block')
// e('a')  -------> fe-block__a
// e('a', 'b')  ------->  fe-block__a fe-block__a--b
export class Bem {
  constructor(b) {
    this.b = `fe-${b}`;
    this.e = (e, state) => {
      if (state) {
        return `${this.b}__${e} ${this.b}__${e}--${state}`;
      }
      return `${this.b}__${e}`;
    };
  }
}
// 空操作
// eslint-disable-next-line no-empty-function
export function noop() {}

export const coerceTruthyValueToArray = function(val) {
  if (Array.isArray(val)) {
    return val;
  } if (val) {
    return [val];
  } 
  return [];
};

export const valueEquals = (a, b) => {
  // see: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
  if (a === b) { return true; }
  if (!(a instanceof Array)) { return false; }
  if (!(b instanceof Array)) { return false; }
  if (a.length !== b.length) { return false; }
  for (let i = 0; i !== a.length; ++i) {
    if (a[i] !== b[i]) { return false; }
  }
  return true;
};

export const generateId = ()=> {
  return Math.floor(Math.random() * 10000);
};


export const looseEqual = function(a, b) {
  const isObjectA = isObject(a);
  const isObjectB = isObject(b);
  if (isObjectA && isObjectB) {
    return JSON.stringify(a) === JSON.stringify(b);
  } if (!isObjectA && !isObjectB) {
    return String(a) === String(b);
  } 
  return false;
  
};

export const capitalize = function(str) {
  if (!isString(str)) { return str; }
  return str.charAt(0).toUpperCase() + str.slice(1);
};

export const kebabCase = function(str) {
  const hyphenateRE = /([^-])([A-Z])/g;
  return str
    .replace(hyphenateRE, '$1-$2')
    .replace(hyphenateRE, '$1-$2')
    .toLowerCase();
};

export const arrayEquals = function(arrayA, arrayB) {
  arrayA = arrayA || [];
  arrayB = arrayB || [];
  if (arrayA.length !== arrayB.length) {
    return false;
  }
  for (let i = 0; i < arrayA.length; i++) {
    if (!looseEqual(arrayA[i], arrayB[i])) {
      return false;
    }
  }
  return true;
};

export const arrayFindIndex = function(arr, pred) {
  for (let i = 0; i !== arr.length; ++i) {
    if (pred(arr[i])) {
      return i;
    }
  }
  return -1;
};

export const arrayFind = function(arr, pred) {
  const idx = arrayFindIndex(arr, pred);
  return idx !== -1 ? arr[idx] : undefined;
};
export const isEqual = function(value1, value2) {
  if (Array.isArray(value1) && Array.isArray(value2)) {
    return arrayEquals(value1, value2);
  }
  return looseEqual(value1, value2);
};

export const escapeRegexpString = (value = '') => String(value).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');

export const isEmpty = function(val) {
  // null or undefined
  if (val == null) { return true; }
  if (typeof val === 'boolean') { return false; }
  if (typeof val === 'number') { return !val; }
  if (val instanceof Error) { return val.message === ''; }
  switch (Object.prototype.toString.call(val)) {
    // String or Array
    case '[object String]':
    case '[object Array]':
      return !val.length;
    // Map or Set or File
    case '[object File]':
    case '[object Map]':
    case '[object Set]': {
      return !val.size;
    }
    // Plain Object
    case '[object Object]': {
      return !Object.keys(val).length;
    }
  }
  return false;
};

export const getValueByPath = function(object, prop) {
  prop = prop || '';
  const paths = prop.split('.');
  let current = object;
  let result = null;
  for (let i = 0, j = paths.length; i < j; i++) {
    const path = paths[i];
    if (!current) { break; }
    if (i === j - 1) {
      result = current[path];
      break;
    }
    current = current[path];
  }
  return result;
};

export function getPropByPath(obj, path, strict) {
  let tempObj = obj;
  path = path.replace(/\[(\w+)\]/g, '.$1');
  path = path.replace(/^\./, '');

  let keyArr = path.split('.');
  let i = 0;
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) { break; }
    let key = keyArr[i];
    if (key in tempObj) {
      tempObj = tempObj[key];
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!');
      }
      break;
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null,
  };
}

export function rafThrottle(fn) {
  let locked = false;
  return function(...args) {
    if (locked) { return; }
    locked = true;
    window.requestAnimationFrame(() => {
      fn.apply(this, args);
      locked = false;
    });
  };
}